Spring MVC 之 <context:annotation-driven/>

版权声明:本文为博主原创文章,转载请注明出处,谢谢!

版权声明:本文为博主原创文章,转载请注明出处:http://blog.jerkybible.com/2015/05/28/Spring MVC 之 contextannotation-driven/

访问原文「Spring MVC 之 <context:annotation-driven/>

一、解析类

通常如果我们希望通过注解的方式来进行Spring MVC开发,我们都会在*-servlet.xml中加入标签来告诉Spring我们的目的。找到对应的实现类是org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser。
通过阅读类注释文档,我们发现这个类主要是用来向工厂中注册了

1
2
3
4
5
6
7
8
RequestMappingHandlerMapping
BeanNameUrlHandlerMapping
RequestMappingHandlerAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver

前两个是HandlerMapping接口的实现类,用来处理请求映射的。其中第一个是处理@RequestMapping注解的。第二个会将controller类的名字映射为请求url。

中间三个是用来处理请求的。具体点说就是确定调用哪个controller的哪个方法来处理当前请求。第一个处理@Controller注解的处理器,支持自定义方法参数和返回值(很酷)。第二个是处理继承HttpRequestHandler的处理器。第三个处理继承自Controller接口的处理器。

后面三个是用来处理异常的解析器。

二、实现流程

首先进入的是xml解析方法。由于annotation-driven不是默认的命名空间,会进入else,使用delegate解析元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Parse the elements at the root level in the document:
* &quot;import&quot;, &quot;alias&quot;, &quot;bean&quot;.
* @param root the DOM root element of the document
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i &lt; nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}

然后会进入下面的方法。这里的Handler获取的是MvcNamespaceHandler。接着可以看到MvcNamespaceHandler中注册的annotation-driven的Parse是AnnotationDrivenBeanDefinitionParser。最后是Parse方法,该方法比较繁琐但是很好理解,注册了上面说的那几个类。

1
2
3
4
5
6
7
8
9
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error(&quot;Unable to locate Spring NamespaceHandler for XML schema namespace [&quot; + namespaceUri + &quot;]&quot;, ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser(&quot;annotation-driven&quot;, new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser(&quot;default-servlet-handler&quot;, new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser(&quot;interceptors&quot;, new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser(&quot;resources&quot;, new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser(&quot;view-controller&quot;, new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser(&quot;redirect-view-controller&quot;, new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser(&quot;status-controller&quot;, new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser(&quot;view-resolvers&quot;, new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser(&quot;tiles-configurer&quot;, new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser(&quot;freemarker-configurer&quot;, new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser(&quot;velocity-configurer&quot;, new VelocityConfigurerBeanDefinitionParser());
registerBeanDefinitionParser(&quot;groovy-configurer&quot;, new GroovyMarkupConfigurerBeanDefinitionParser());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
//第一个在这 RequestMappingHandlerMapping
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add(&quot;order&quot;, 0);
handlerMappingDef.getPropertyValues().add(&quot;contentNegotiationManager&quot;, contentNegotiationManager);
String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef);
if (element.hasAttribute(&quot;enable-matrix-variables&quot;)) {
Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute(&quot;enable-matrix-variables&quot;));
handlerMappingDef.getPropertyValues().add(&quot;removeSemicolonContent&quot;, !enableMatrixVariables);
}
else if (element.hasAttribute(&quot;enableMatrixVariables&quot;)) {
Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute(&quot;enableMatrixVariables&quot;));
handlerMappingDef.getPropertyValues().add(&quot;removeSemicolonContent&quot;, !enableMatrixVariables);
}
configurePathMatchingProperties(handlerMappingDef, element, parserContext);
RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
RuntimeBeanReference validator = getValidator(element, source, parserContext);
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
bindingDef.setSource(source);
bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
bindingDef.getPropertyValues().add(&quot;conversionService&quot;, conversionService);
bindingDef.getPropertyValues().add(&quot;validator&quot;, validator);
bindingDef.getPropertyValues().add(&quot;messageCodesResolver&quot;, messageCodesResolver);
ManagedList&lt;?&gt; messageConverters = getMessageConverters(element, source, parserContext);
ManagedList&lt;?&gt; argumentResolvers = getArgumentResolvers(element, parserContext);
ManagedList&lt;?&gt; returnValueHandlers = getReturnValueHandlers(element, parserContext);
String asyncTimeout = getAsyncTimeout(element);
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
ManagedList&lt;?&gt; callableInterceptors = getCallableInterceptors(element, source, parserContext);
ManagedList&lt;?&gt; deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);
//第二个在这 RequestMappingHandlerAdapter
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerAdapterDef.getPropertyValues().add(&quot;contentNegotiationManager&quot;, contentNegotiationManager);
handlerAdapterDef.getPropertyValues().add(&quot;webBindingInitializer&quot;, bindingDef);
handlerAdapterDef.getPropertyValues().add(&quot;messageConverters&quot;, messageConverters);
addResponseBodyAdvice(handlerAdapterDef);
if (element.hasAttribute(&quot;ignore-default-model-on-redirect&quot;)) {
Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute(&quot;ignore-default-model-on-redirect&quot;));
handlerAdapterDef.getPropertyValues().add(&quot;ignoreDefaultModelOnRedirect&quot;, ignoreDefaultModel);
}
else if (element.hasAttribute(&quot;ignoreDefaultModelOnRedirect&quot;)) {
// &quot;ignoreDefaultModelOnRedirect&quot; spelling is deprecated
Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute(&quot;ignoreDefaultModelOnRedirect&quot;));
handlerAdapterDef.getPropertyValues().add(&quot;ignoreDefaultModelOnRedirect&quot;, ignoreDefaultModel);
}
if (argumentResolvers != null) {
handlerAdapterDef.getPropertyValues().add(&quot;customArgumentResolvers&quot;, argumentResolvers);
}
if (returnValueHandlers != null) {
handlerAdapterDef.getPropertyValues().add(&quot;customReturnValueHandlers&quot;, returnValueHandlers);
}
if (asyncTimeout != null) {
handlerAdapterDef.getPropertyValues().add(&quot;asyncRequestTimeout&quot;, asyncTimeout);
}
if (asyncExecutor != null) {
handlerAdapterDef.getPropertyValues().add(&quot;taskExecutor&quot;, asyncExecutor);
}
handlerAdapterDef.getPropertyValues().add(&quot;callableInterceptors&quot;, callableInterceptors);
handlerAdapterDef.getPropertyValues().add(&quot;deferredResultInterceptors&quot;, deferredResultInterceptors);
String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef);
String uriCompContribName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
RootBeanDefinition uriCompContribDef = new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
uriCompContribDef.setSource(source);
uriCompContribDef.getPropertyValues().addPropertyValue(&quot;handlerAdapter&quot;, handlerAdapterDef);
uriCompContribDef.getPropertyValues().addPropertyValue(&quot;conversionService&quot;, conversionService);
parserContext.getReaderContext().getRegistry().registerBeanDefinition(uriCompContribName, uriCompContribDef);
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedCsInterceptorDef.setSource(source);
mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef);
RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
exceptionHandlerExceptionResolver.setSource(source);
exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
exceptionHandlerExceptionResolver.getPropertyValues().add(&quot;contentNegotiationManager&quot;, contentNegotiationManager);
exceptionHandlerExceptionResolver.getPropertyValues().add(&quot;messageConverters&quot;, messageConverters);
exceptionHandlerExceptionResolver.getPropertyValues().add(&quot;order&quot;, 0);
addResponseBodyAdvice(exceptionHandlerExceptionResolver);
String methodExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver);
RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
responseStatusExceptionResolver.setSource(source);
responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
responseStatusExceptionResolver.getPropertyValues().add(&quot;order&quot;, 1);
String responseStatusExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(responseStatusExceptionResolver);
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
defaultExceptionResolver.setSource(source);
defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
defaultExceptionResolver.getPropertyValues().add(&quot;order&quot;, 2);
String defaultExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(defaultExceptionResolver);
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, methodMappingName));
parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName));
parserContext.registerComponent(new BeanComponentDefinition(uriCompContribDef, uriCompContribName));
parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not &quot;turned off&quot;
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
parserContext.popAndRegisterContainingComponent();
return null;
}

三、总结
主要说明里面的两个,RequestMappingHandlerMapping和RequestMappingHandlerAdapter。

第一个是HandlerMapping的实现类,它会处理@RequestMapping 注解,并将其注册到请求映射表中。(下片文章我们会详细介绍的)

第二个是HandlerAdapter的实现类,它是处理请求的适配器,说白了,就是确定调用哪个类的哪个方法,并且构造方法参数,返回值。(后面文章也会陆续详细介绍的)

那么它跟<context:component-scan/>的区别是,<context:component-scan/>标签是告诉Spring 来扫描指定包下的类,并注册被@Component,@Controller,@Service,@Repository等注解标记的组件。

而<mvc:annotation-scan/>是告知Spring,我们启用注解驱动。然后Spring会自动为我们注册上面说到的几个Bean到工厂中,来处理我们的请求。
Jerky Lu wechat
欢迎加入微信公众号